﻿/// <reference path="../Scripts/jquery-1.7.2.js" />
/// <reference path="../Scripts/knockout-2.1.0.js" />
/// <reference path="../Scripts/knockout.mapping-latest.js" />
/// <reference path="../Scripts/qunit.js" />
/// <reference path="../Scripts/sinon-1.3.4.js" />
/// <reference path="../Scripts/sinon-qunit-1.0.0.js" />



/// <reference path="../aaa/ActivityFeed.Web/Scripts/activityFeed.utils.js" />
/// <reference path="../aaa/ActivityFeed.Web/Scripts/activityFeed.jQueryPlugins.js" />
/// <reference path="../aaa/ActivityFeed.Web/Scripts/activityFeed.knockout.js" />
/// <reference path="../aaa/ActivityFeed.Web/Scripts/activityFeed.viewModels.ActivityFeed.js" />
/// <reference path="../aaa/ActivityFeed.Web/Scripts/activityFeed.viewModels.Update.js" />
/// <reference path="../aaa/ActivityFeed.Web/Scripts/activityFeed.viewModels.Comment.js" />





$(function () {
    module("");

    test("When ActivityFeedViewModel is created, then provided updates are wrapped into observables.", function () {
        var initialUpdates = [{ id: 1, content: "EloMelo" }, { id: 2, content: "EloMelo"}];
        var viewModel = new activityFeed.ActivityFeedViewModel({ user: {}, source: "web", updates: initialUpdates, topicsFilter: null }
    );

        equal(viewModel.updates().length, initialUpdates.length);
        ok(viewModel.updates()[0].id());
        ok(viewModel.updates()[0].content());
    });

    test("When ActivityFeedViewModel is created, then provided updates contain deserialized publishedOn date.", function () {
        var publishedOn = new Date(1337089291151);
        var initialUpdates = [{ id: 1, content: "EloMelo", publishedOn: publishedOn.toISOString()}];
        var viewModel = new activityFeed.ActivityFeedViewModel({ user: {}, source: "web", updates: initialUpdates, topicsFilter: null });

        var date = viewModel.updates()[0].publishedOn();
        equal(date.toISOString(), publishedOn.toISOString());
    });

    test("When onInitialize method is provided, then it's executed in init mehtod of activityFeedViewModel", function () {
        var onInitializeMock = sinon.spy("onInitialize");
        window["onInitializeTest"] = onInitializeMock;
        var viewModel = new activityFeed.ActivityFeedViewModel({ user: {}, source: "web", updates: [], topicsFilter: null, onInitialize: "onInitializeTest" });
        viewModel.initialize();
        equal(onInitializeMock.callCount, 1);
    });

    test("When onUpdateViewModelInitialize method is provided, then each update is extended with this method", function () {
        var onUpdateInitializeMock = sinon.spy("onUpdateInitialize");
        window["onUpdateInitialize"] = onUpdateInitializeMock;
        var initialUpdates = [{ id: 1, content: "EloMelo" }, { id: 2, content: "EloMelo2"}];
        var viewModel = new activityFeed.ActivityFeedViewModel({ user: {}, source: "web", updates: initialUpdates, topicsFilter: null, onUpdateViewModelInitialize: "onUpdateInitialize" });
        viewModel.initialize();
        equal(onUpdateInitializeMock.callCount, 2);
    });

    test("When onUpdateViewModelInitialize method is provided, but method not exists in global scope then exception is thrown", function () {
        var viewModel = new activityFeed.ActivityFeedViewModel({ user: {}, source: "web", updates: [], topicsFilter: null, onUpdateViewModelInitialize: "onUpdateInitializeNotExists" });
        raises(viewModel.initialize, "Error message", "Exception should be thrown");
    });

});

$(function () {

    var apiMock;
    var viewModel;


    // ***** ***** ***** ***** ***** 
    // *****  
    // *****  E M P T Y      S T A T U S
    // *****  U P D A T E    T E X T
    // *****  
    // ***** ***** ***** ***** ***** 
    module("Given empty newPostText", {
        setup: function () {
            apiMock = sinon.mock(activityFeed.api);

            viewModel = new activityFeed.ActivityFeedViewModel({ user: {}, source: "web", updates: [{}], topicsFilter: null });
            viewModel.newPostText("");
        },
        teardown: function () {
            apiMock.restore();
        }
    });

    test("When postUpdate is called, then update is not added to updates.", function () {
        var expectedUpdatesCount = viewModel.updates().length;
        viewModel.postUpdate();
        equal(viewModel.updates().length, expectedUpdatesCount);
    });

    test("When postUpdate is called, then api is not called.", function () {
        apiMock.expects("postUpdate").never();
        viewModel.postUpdate();
        ok(apiMock.verify(), "Check API");
    });

    // ***** ***** ***** ***** ***** 
    // *****  
    // *****  P O S T    U P D A T E
    // *****  
    // ***** ***** ***** ***** ***** 
    module("Given authenticated user and non empty newPostText", {
        setup: function () {
            apiMock = sinon.mock(activityFeed.api);

            viewModel = new activityFeed.ActivityFeedViewModel({
                user: { id: 'UserId', name: 'User Name', photoUrl: 'http://user.photo/url' },
                source: "web",
                updates: [{}],
                newTopics: null
            });
            viewModel.newPostText("testText");
        },
        teardown: function () {
            apiMock.restore();
        }
    });

    test("After postUpdate onUpdateViewModelInitialize is called for new update", function () {
        var onUpdateInitializeMock = sinon.spy("onUpdateInitialize");
        window["onUpdateInitialize"] = onUpdateInitializeMock;

        var viewModel = new activityFeed.ActivityFeedViewModel({ user: {}, source: "web", updates: [], topicsFilter: null, onUpdateViewModelInitialize: "onUpdateInitialize" });
        viewModel.initialize();

        var result = $.Deferred();
        apiMock.expects("postUpdate").returns(result);

        viewModel.newPostText("EloMelo3");
        viewModel.postUpdate().then(function () {
            equal(onUpdateInitializeMock.callCount, 1);
        });
        result.resolve({ value: { id: "upd1111"} });

    });

    test("When postUpdate, then new update is added after API is resolved.", function () {
        var result = $.Deferred();
        apiMock.expects("postUpdate").returns(result);

        var updatesLength = viewModel.updates().length;

        viewModel.postUpdate().then(function (update) {
            equal(viewModel.updates().length, updatesLength + 1, "Update should be added");
        });

        equal(viewModel.updates().length, updatesLength, "Update should not be added yet");

        result.resolve({ value: { id: "upd1111"} });
    });

    test("When postUpdate with newTopics assigned, then API is called with proper parameters.", function () {
        var newTopics = ['topic1', 'topic2'];

        var viewModelWithTopics = new activityFeed.ActivityFeedViewModel({
            user: { id: 'UserId', name: 'User Name', photoUrl: 'http://user.photo/url' },
            source: "web",
            updates: [{}],
            newTopics: newTopics
        });

        apiMock.expects("postUpdate").withExactArgs('testText', 'web', newTopics).returns($.Deferred());

        viewModelWithTopics.newPostText("testText");
        viewModelWithTopics.postUpdate();

        ok(apiMock.verify(), "Check API");
    });

    test("When postUpdate is called, then api is called with apriopriate text.", function () {
        apiMock.expects("postUpdate").withExactArgs("testText", "web", null).returns($.Deferred());
        viewModel.postUpdate();
        ok(apiMock.verify(), "Check API");
    });

    test("After postUpdate is resolved, update.id is assigned.", function () {
        var result = $.Deferred();
        apiMock.expects("postUpdate").returns(result);

        viewModel.postUpdate().then(function (update) {
            ok(update.id());
        });

        result.resolve({ value: { id: 123} });
    });

    test("After postUpdate API is resolved, then newPostText is empty.", function () {
        var statusUpdateText = viewModel.newPostText();
        var result = $.Deferred();

        apiMock.expects("postUpdate").returns(result);

        viewModel.postUpdate().then(function (update) {
            equal(viewModel.newPostText(), "");
        });

        equal(viewModel.newPostText(), statusUpdateText);

        result.resolve({ value: { id: "upd222"} });
    });


    module("removeUpdate: Given authenticated user and update in updates", {
        setup: function () {
            apiMock = sinon.mock(activityFeed.api);

            viewModel = new activityFeed.ActivityFeedViewModel({
                user: { id: 'UserId', name: 'User Name', photoUrl: 'http://user.photo/url' },
                source: "web",
                updates: [{ id: 'updateId', content: 'test test test', publisher: { id: 'UserId', name: 'john smith' }, publishedOn: (new Date(1337089291151)).toISOString()}],
                topicsFilter: null
            });
        },
        teardown: function () {
            apiMock.restore();
        }
    });

    test("After removeUpdate is called, then update is removed after API resolves.", function () {
        var result = $.Deferred();
        apiMock.expects("removeUpdate").returns(result);
        var updateToRemove = viewModel.updates()[0];

        updateToRemove.removeUpdate().then(function () {
            equal(viewModel.updates.indexOf(updateToRemove), -1);
        });

        notEqual(viewModel.updates.indexOf(updateToRemove), -1);

        result.resolve();
    });


    // ***** ***** ***** ***** ***** 
    // *****  
    // *****  T O P I C S    F I L T E R
    // *****  
    // ***** ***** ***** ***** ***** 
    module("TopicsFilter: Given authenticated user and topicsFilter context", {
        setup: function () {
            apiMock = sinon.mock(activityFeed.api);

            viewModel = new activityFeed.ActivityFeedViewModel({
                feedType: 'personal',
                user: { id: 'UserId', name: 'User Name', photoUrl: 'http://user.photo/url' },
                source: "web",
                updates: [{ id: 'updateId', content: 'test test test', publishedBy: 'userId', publisherName: 'john smith', publishedOn: (new Date(1337089291151)).toISOString()}],
                topicsFilter: ['cms-12345', 'cms-222', 'cms-333'],
                pageSize: 10
            });
            viewModel.initialize();
        },
        teardown: function () {
            apiMock.restore();
        }
    });

    test("After getUpdates is called, then topicsFilter is passed to api.", function () {
        apiMock.expects("getUpdates").withExactArgs("personal", null, "", null, 10, ['cms-12345', 'cms-222', 'cms-333']).returns($.Deferred());
        viewModel.refreshUpdates();
        ok(apiMock.verify(), "Check API");
    });


    // ***** ***** ***** ***** ***** 
    // *****  
    // *****  C O M M E N T S
    // *****  
    // ***** ***** ***** ***** ***** 
    module("comments: Given authenticated user and initial updates", {
        setup: function () {
            apiMock = sinon.mock(activityFeed.api);

            viewModel = new activityFeed.ActivityFeedViewModel({
                user: { id: 'UserId', name: 'User Name', photoUrl: 'http://user.photo/url' },
                source: "web",
                updates: [{ id: 'updateId', content: 'test test test', publishedBy: 'userId', publisherName: 'john smith', publishedOn: (new Date(1337089291151)).toISOString()}],
                topicsFilter: null,
                newTopics: null
            });
        },
        teardown: function () {
            apiMock.restore();
        }
    });

    // basic checks
    test("After postUpdate is called, then update contains observableArray comments.", function () {
        apiMock.expects("postUpdate").withExactArgs("testText", "web", null).returns($.Deferred());
        viewModel.newPostText("testText");
        viewModel.postUpdate();
        ok(viewModel.updates()[0].comments());
    });

    // postComment
    test("When user post an empty comment then comment is not added to array.", function () {
        apiMock.expects("postComment").returns($.Deferred());

        var update = viewModel.updates()[0];
        update.newCommentText("");
        update.postNewComment();

        equal(update.comments().length, 0);
    });

    test("When user post a comment then comment is added at the end of array after API is resolved.", function () {
        var result = $.Deferred();
        apiMock.expects("postComment").returns(result);

        var update = viewModel.updates()[0];

        // fake comment
        var comment = new activityFeed.CommentViewModel();
        comment.text("old comment");
        update.comments.push(comment);

        var commentsLength = update.comments().length;

        update.newCommentText("new comment");
        update.postNewComment().then(function (res) {
            equal(update.comments()[update.comments().length - 1].text(), "new comment");
        });

        equal(update.comments().length, commentsLength, "Comment should not be added yet");

        result.resolve({ value: { id: 'comment1111', text: 'new comment'} });
    });

    test("When user post a comment then api is called with proper parameters.", function () {
        apiMock.expects("postComment").withExactArgs("update11", "new comment").returns($.Deferred());

        var update = viewModel.updates()[0];
        update.id("update11");
        update.newCommentText("new comment");
        update.postNewComment();

        ok(apiMock.verify(), "Check API");
    });

    test("After postNewComment is resolved, comment.id is assigned.", function () {
        var result = $.Deferred();
        apiMock.expects("postComment").returns($.Deferred());

        var update = viewModel.updates()[0];
        update.newCommentText("new comment");
        update.postNewComment().then(function (u) {
            ok(u.id());
        });

        result.resolve({ comment: { id: "111"} });
    });

    test("After postNewComment is called, then after API is resolved newCommentText become empty.", function () {
        var result = $.Deferred();
        apiMock.expects("postComment").returns(result);

        var update = viewModel.updates()[0];
        update.newCommentText("new comment");
        update.postNewComment().then(function () {
            equal(update.newCommentText(), "");
        });

        equal(update.newCommentText(), "new comment", "Comment should not be empty yet");

        result.resolve({ value: { id: "12345"} });
    });


    // removeComment
    test("When removeComment is called, After API is resolved, then comment is removed from comments array.", function () {
        var result = $.Deferred();
        apiMock.expects("removeComment").returns(result);

        var update = viewModel.updates()[0];
        var comment = new activityFeed.CommentViewModel({ id: "currentUserId" }, update.removeCommentHandler);
        comment.publisher({ id: "currentUserId" });
        comment.id("comment1");
        update.comments.push(comment);

        comment.removeComment().then(function () {
            equal(update.comments().length, 0, "Comment was removed");
        });

        equal(update.comments().length, 1, "Comment is not removed");
    });

    test("When removeComment, then api.removeComment is called with proper parameters.", function () {
        var update = viewModel.updates()[0];
        var comment = new activityFeed.CommentViewModel({ id: "currentUserId" }, update.removeCommentHandler);
        comment.id("comment1");
        comment.publisher({ id: "currentUserId" });
        update.comments.push(comment);

        apiMock.expects("removeComment").withExactArgs(update.id(), comment.id()).returns($.Deferred());

        comment.removeComment();

        ok(apiMock.verify(), "Check API");
    });


    // ***** ***** ***** ***** ***** 
    // *****  
    // *****  L I K E S
    // *****  
    // ***** ***** ***** ***** ***** 
    module("likes: Given authenticated user and initial updates", {
        setup: function () {
            apiMock = sinon.mock(activityFeed.api);

            this.currentUser = { id: 'UserId', name: 'User Name', photoUrl: 'http://user.photo/url' };

            this.pageSize = 10;
            viewModel = new activityFeed.ActivityFeedViewModel({
                user: { id: 'UserId', name: 'User Name', photoUrl: 'http://user.photo/url' },
                source: "web",
                updates: [{ id: 'updateId', content: 'test test test', publishedBy: 'userId', publisherName: 'john smith', publishedOn: (new Date(1337089291151)).toISOString()}],
                topicsFilter: null,
                pageSize: this.pageSize
            });
        },
        teardown: function () {
            apiMock.restore();
        }
    });

    // hasLikes
    test("When update do not contain likes then hasLikes returns false", function () {
        equal(viewModel.updates()[0].hasLikes(), false);
    });


    // likedByMe
    test("When likes do not contain current user, then likedByMe returns false.", function () {
        var update = viewModel.updates()[0];
        update.likes.push(new activityFeed.LikeViewModel(this.currentUser));
        var like = update.likes()[0];
        like.user({ id: 'Diffrent UserId' });

        equal(update.likedByMe(), false);
    });

    test("When likes contains user, then likedByMe returns true.", function () {
        var update = viewModel.updates()[0];
        update.likes.push(new activityFeed.LikeViewModel(this.currentUser));
        var like = update.likes()[0];
        like.user({ id: 'UserId' });

        equal(update.likedByMe(), true);
    });

    // add like
    test("When user call toggleLike and update do not have Id, then API is not called.", function () {
        var result = $.Deferred();
        apiMock.expects("likeUpdate").never().returns(result);

        var update = new activityFeed.UpdateViewModel(this.currentUser);
        update.id('');

        update.toggleLike();
        ok(apiMock.verify(), "Check API");
    });

    test("When user call toggleLike, after API is resolved, then like is added to likes list.", function () {
        var result = $.Deferred();
        apiMock.expects("likeUpdate").returns(result);

        var update = viewModel.updates()[0];
        update.toggleLike().then(function () {
            equal(update.likedByMe(), true, "Like added");
            ok(update.likes()[0].user(), "User is assigned to like");
        });

        equal(update.likedByMe(), false, "Like not added yet");

        result.resolve({ value: { user: this.currentUser} });
    });

    test("When user likes update, then api is called with proper parameters.", function () {
        var update = viewModel.updates()[0];

        apiMock.expects("likeUpdate").withExactArgs(update.id()).returns($.Deferred());

        update.toggleLike();

        ok(apiMock.verify(), "Check API");
    });


    // remove like
    test("When user remove like from update, after API is resolved, then like is removed from likes list.", function () {
        var result = $.Deferred();
        apiMock.expects("likeUpdate");
        apiMock.expects("removeLikeFromUpdate").returns(result);

        var update = viewModel.updates()[0];
        // add
        update.likes.push(new activityFeed.LikeViewModel());
        var like = update.likes()[0];
        like.user({ id: this.currentUser.id });

        // remove
        update.toggleLike().then(function () {
            equal(update.likedByMe(), false, "Like removed");
        });

        equal(update.likedByMe(), true, "Like not removed yet");

        result.resolve();
    });

    test("When user remove like from update, then api is called with proper parameters.", function () {
        var update = viewModel.updates()[0];

        // add fake
        update.likes.push(new activityFeed.LikeViewModel());
        var like = update.likes()[0];
        like.user({ id: 'UserId' });

        apiMock.expects("removeLikeFromUpdate").withExactArgs(update.id()).returns($.Deferred());

        update.toggleLike();

        ok(apiMock.verify(), "Check API");
    });



    module("likes: Given authenticated user and initial updates with likes", {
        setup: function () {
            apiMock = sinon.mock(activityFeed.api);

            this.pageSize = 10;
            viewModel = new activityFeed.ActivityFeedViewModel({
                feedType: 'personal',
                customFeedTypeName: 'customFeedTypeNameTest',
                user: { id: 'CurrentUserId', name: 'User Name', photoUrl: 'http://user.photo/url' },
                source: "web",
                updates: [{
                    id: 'updateId',
                    content: 'test test test',
                    publishedBy: 'userId',
                    publisherName: 'john smith',
                    likes:
                        [
                            { user: { id: 'CurrentUserId' }, createdDate: (new Date(1337089291151)).toISOString() },
                            { user: { id: 'User2' }, createdDate: (new Date(1337089291151)).toISOString() },
                            { user: { id: 'User3' }, createdDate: (new Date(1337089291151)).toISOString() },
                            { user: { id: 'User4' }, createdDate: (new Date(1337089291151)).toISOString() },
                            { user: { id: 'User5' }, createdDate: (new Date(1337089291151)).toISOString() },
                            { user: { id: 'User6' }, createdDate: (new Date(1337089291151)).toISOString() },
                            { user: { id: 'User7' }, createdDate: (new Date(1337089291151)).toISOString() },
                            { user: { id: 'User8' }, createdDate: (new Date(1337089291151)).toISOString() },
                            { user: { id: 'User9' }, createdDate: (new Date(1337089291151)).toISOString() }
                        ],
                    publishedOn: (new Date(1337089291151)).toISOString()
                }],
                topicsFilter: null,
                pageSize: this.pageSize
            });
        },
        teardown: function () {
            apiMock.restore();
        }
    });

    test("When update contain likes then hasLikes returns true", function () {
        equal(viewModel.updates()[0].hasLikes(), true);
    });

    test("When current user already like update then likesExcludingMine do not contain current user", function () {
        var updatesCount = viewModel.updates()[0].likes().length;
        var likesExcludingMine = viewModel.updates()[0].likesExcludingMine();
        equal(likesExcludingMine.length, updatesCount - 1);
    });

    test("When likesExcludingMine.take is used then limited number of likes are returned", function () {
        var updatesCount = viewModel.updates()[0].likes().length;

        equal(viewModel.updates()[0].likesExcludingMine().take(3).length, 3);
    });

    // ***** ***** ***** ***** *****  ***** *****
    // *****  
    // *****  R E F R E S H    U P D A T E S
    // *****  
    // ***** ***** ***** ***** *****  ***** *****

    test("When refresh updates, then api is called with proper parameters.", function () {
        apiMock.expects("getUpdates").once().withExactArgs('personal', 'customFeedTypeNameTest', "test search", null, this.pageSize, null).returns($.Deferred());
        viewModel.searchTerm("test search");
        viewModel.refreshUpdates();

        ok(apiMock.verify(), "Check API");
    });

    test("When refresh updates, then new updates are assigned to updates list.", function () {
        var newUpdates = [{ id: 'newUpdateId', content: 'test test test', publishedBy: 'userId', publisherName: 'john smith', publishedOn: (new Date(1337089291151)).toISOString()}];

        var result = new $.Deferred();
        apiMock.expects("getUpdates").returns(result);
        viewModel.refreshUpdates().then(function () {
            equal(viewModel.updates().length, newUpdates.length);
            equal(viewModel.updates()[0].id(), 'newUpdateId');
        });

        result.resolve({ value: newUpdates });
    });


    // ***** ***** ***** ***** *****  ***** *****
    // *****  
    // *****  P A G I N G
    // *****  
    // ***** ***** ***** ***** *****  ***** *****
    module("likes: Given authenticated user and initial updates", {
        setup: function () {
            apiMock = sinon.mock(activityFeed.api);

            this.pageSize = 5;

            viewModel = new activityFeed.ActivityFeedViewModel({
                feedType: 'personal',
                customFeedTypeName: 'customFeedTypeNameTest',
                user: { id: 'UserId', name: 'User Name', photoUrl: 'http://user.photo/url' },
                source: "web",
                updates: [{ id: 'updateId', content: 'test test test', publishedBy: 'userId', publisherName: 'john smith', publishedOn: (new Date(1337089291151)).toISOString()}],
                topicsFilter: null,
                pageSize: this.pageSize
            });
        },
        teardown: function () {
            apiMock.restore();
        }
    });

    test("When loadNextPage is called, then api is called with proper parameters.", function () {

        var dateFrom = viewModel.updates()[0].publishedOn().toISOString();
        apiMock.expects("getUpdates").withExactArgs('personal', 'customFeedTypeNameTest', '', dateFrom, this.pageSize, null).returns($.Deferred());
        viewModel.loadNextPage();
        ok(apiMock.verify(), "Check API");
    });

    test("When loadNextPage is called, then onUpdateViewModelInitialize is called for all updates.", function () {
        var getUpdatesResult = $.Deferred();
        apiMock.expects("getUpdates").returns(getUpdatesResult);

        var onUpdateInitializeMock = sinon.spy("onUpdateInitialize");
        window["onUpdateInitialize"] = onUpdateInitializeMock;
        var newUpdates = [{ id: 1, content: "EloMelo" }, { id: 2, content: "EloMelo2"}];
        viewModel = new activityFeed.ActivityFeedViewModel({
            updates: [],
            onUpdateViewModelInitialize: "onUpdateInitialize"
        });
        viewModel.initialize();
        viewModel.loadNextPage();
        getUpdatesResult.resolve({ value: newUpdates });

        equal(onUpdateInitializeMock.callCount, 2);
    });

    test("When loadNextPage is called, then new updates are added to the end of the updates list.", function () {
        var currentUpdateLength = viewModel.updates().length;
        var dateFrom = viewModel.updates()[0].publishedOn();
        var newUpdates = [{ id: 'newUpdateId', content: 'test test test', publishedBy: 'userId', publisherName: 'john smith', publishedOn: (new Date(1337089291151)).toISOString()}];

        var result = new $.Deferred();
        apiMock.expects("getUpdates").returns(result);
        viewModel.loadNextPage().then(function () {
            equal(viewModel.updates().length, currentUpdateLength + newUpdates.length);

            var lastUpdateInArray = viewModel.updates()[viewModel.updates().length - 1].publishedOn();
            var lastUpdateInNewList = new Date(Date.parse(newUpdates[newUpdates.length - 1].publishedOn));
            equal(lastUpdateInArray.toString(), lastUpdateInNewList.toString(), "Check publishedOn");
        });

        equal(viewModel.updates().length, currentUpdateLength);

        result.resolve({ value: newUpdates });
    });


    // ***** ***** ***** ***** *****  ***** *****
    // *****  
    // *****  H A S   M O R E   U P D A T E S
    // *****  
    // ***** ***** ***** ***** *****  ***** *****
    test("When viewModel is initialized with complete list, then hasMoreUpdates return false and loadNextPage is disabled", function () {
        var testViewModel = new activityFeed.ActivityFeedViewModel({ source: 'web', updates: [], isListOfUpdatesComplete: true });
        ok(testViewModel.hasMoreUpdates() == false, "More updates are not available");
        ok(testViewModel.loadNextPage.isEnabled() == false, "loadNextPage is disabled");
    });

    test("When viewModel is initialized with partial list, then hasMoreUpdates return true", function () {
        var testViewModel = new activityFeed.ActivityFeedViewModel({ source: 'web', updates: [], isListOfUpdatesComplete: false });
        ok(testViewModel.hasMoreUpdates(), "More updates are available");
        ok(testViewModel.loadNextPage.isEnabled() == true, "loadNextPage is enabled");
    });

    test("When loadNextPage is called and 'Complete' returns false, then hasMoreUpdates return true.", function () {

        var dateFrom = viewModel.updates()[0].publishedOn().toISOString();
        var result = $.Deferred();
        apiMock.expects("getUpdates").withExactArgs('personal', 'customFeedTypeNameTest', '', dateFrom, this.pageSize, null).returns(result);

        viewModel.loadNextPage().then(function () {
            equal(viewModel.hasMoreUpdates(), true, "More updates are available");
        });

        result.resolve({ value: [], complete: false });
    });

    test("When loadNextPage is called and 'Complate' returns true, then hasMoreUpdates return false.", function () {

        var dateFrom = viewModel.updates()[0].publishedOn().toISOString();
        var result = $.Deferred();
        apiMock.expects("getUpdates").withExactArgs('personal', 'customFeedTypeNameTest', '', dateFrom, this.pageSize, null).returns(result);

        viewModel.loadNextPage().then(function () {
            equal(viewModel.hasMoreUpdates(), false, "More updates are available");
        });

        result.resolve({ value: [], complete: true });
    });



    // ***** ***** ***** ***** *****  ***** *****
    // *****  
    // *****  S E A R C H
    // *****  
    // ***** ***** ***** ***** *****  ***** *****

    test("When searchTerm is assigned, then api is called with proper parameters.", function () {

        this.clock = sinon.useFakeTimers();

        apiMock.expects("getUpdates").withExactArgs('personal', 'customFeedTypeNameTest', "test", null, this.pageSize, null).returns($.Deferred());

        viewModel.searchTerm("test");

        this.clock.tick(500);

        ok(apiMock.verify(), "Check API");

        this.clock.restore();
    });
});